﻿//*****************************************************************************
// Source: http://www.codeproject.com/KB/WF/DynamicSendActivity.aspx
//*****************************************************************************
//
using System;
using System.Activities;
using System.Activities.Presentation;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceModel.Activities;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.Windows;
using System.Windows.Markup;
using System.Xml.Linq;

namespace TfsCloudDeploy.Workflow.Core.DeploymentService.Activities
{
    [ContentProperty("Body")]
    [DesignTimeVisible(false)]
    public sealed class BindingScope : NativeActivity
    {
        [Category("Input")]
        [DefaultValue((string)null)]
        public InArgument<dynamic> Binding { get; set; }

        [Category("Input")]
        [DefaultValue((string)null)]
        public InArgument<dynamic> Headers { get; set; }

        [Browsable(false)]
        public Send Body { get; set; }

        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            if (this.Body == null)
                metadata.AddValidationError("Missing a Send Activity in the scope");

            if (this.Body != null && this.Body.Endpoint == null)
                this.Body.Endpoint = new Endpoint() { Binding = new BasicHttpBinding(), AddressUri = new Uri("http://localhost/Fake") };

            Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();
            if (this.Binding != null)
            {
                RuntimeArgument argumentBinding = new RuntimeArgument("Binding", typeof(object), ArgumentDirection.In, true);
                metadata.Bind(this.Binding, argumentBinding);
                arguments.Add(argumentBinding);
            }

            if (this.Headers != null)
            {
                RuntimeArgument argumentHeaders = new RuntimeArgument("Headers", typeof(object), ArgumentDirection.In, true);
                metadata.Bind(this.Headers, argumentHeaders);
                arguments.Add(argumentHeaders);
            }

            metadata.SetArgumentsCollection(arguments);
            metadata.AddChild(Body);
        }

        protected override void Execute(NativeActivityContext context)
        {
            // inject headers
            if (this.Headers != null)
            {
                context.Properties.Add("MessageInspector", new SendMessageInspector() { MessageHeaders = this.Headers.Get(context) });
            }

            // update binding
            if (this.Binding != null)
            {
                dynamic dynBinding = this.Binding.Get(context);

                if (dynBinding is XElement || dynBinding is string)
                {
                    XElement bindingElement = dynBinding is XElement ? dynBinding : XElement.Parse(dynBinding);
                    var bs = LibHelper.DeserializeSection<BindingsSection>(string.Concat("<bindings>", bindingElement.ToString(), "</bindings>"));
                    var bce = bs.BindingCollections.Find(b => b.BindingName == bindingElement.Name.LocalName);

                    Binding binding = Activator.CreateInstance(bce.BindingType) as Binding;
                    if (bce.ConfiguredBindings.Count == 1)
                        bce.ConfiguredBindings[0].ApplyConfiguration(binding);

                    this.Body.Endpoint.Binding = binding;
                }
                else
                {
                    this.Body.Endpoint.Binding = dynBinding;
                }
            }

            context.ScheduleActivity(Body, OnFaulted);
        }

        private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
        {
        }
    }


    public class BindingScopeFactory : IActivityTemplateFactory
    {
        public Activity Create(DependencyObject target)
        {
            return new BindingScope()
            {
                DisplayName = "BindingScope",
                Body = new Send()
                {
                    Action = "*",
                    OperationName = "ProcessMessage",
                    ServiceContractName = "IGenericContract",
                    Endpoint = new Endpoint()
                    {
                        Binding = new BasicHttpBinding()
                    }
                }
            };
        }
    }
}


